/*
   Copyright 2009 Abdulla Abdurakhmanov (abdulla@latestbit.com)
   Original sources are available at www.latestbit.com

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package org.latestbit.smartobjects.network.tests;

import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.latestbit.smartobjects.network.ConnectionHandler;
import org.latestbit.smartobjects.network.IManagedConnection;
import org.latestbit.smartobjects.network.IManagedConnectionListener;
import org.latestbit.smartobjects.network.IManagedStreamListener;

public class ManagedConnectionListenerTester implements
		IManagedConnectionListener, IManagedStreamListener {

	private static final long DEFAULT_AWAIT_TIME = 15;
	private Lock conditionLock = new ReentrantLock();
	
	private Condition condition = conditionLock.newCondition();
	
	private Lock conditionPerHandlerLock = new ReentrantLock();
	
	private Condition conditionPerHandler = conditionPerHandlerLock.newCondition();
	
	private boolean connected = false;
	private String errorMessage;
	private Collection<ConnectionHandler> lastHandlers = new LinkedList<ConnectionHandler>();

	public void waitCondition() throws InterruptedException, TimeoutException {
		if(!condition.await(DEFAULT_AWAIT_TIME, TimeUnit.SECONDS))
			throw new TimeoutException("Timeout occured for waiting event");
	}
	
	
	public Lock getConditionLock() {
		return this.conditionLock;
	}
	
	public void signalCondition() {
		conditionLock.lock();
		condition.signal();
		conditionLock.unlock();
	}
	
	public void waitConditionPerHandler() throws InterruptedException, TimeoutException {
		if(!conditionPerHandler.await(DEFAULT_AWAIT_TIME, TimeUnit.SECONDS))
			throw new TimeoutException("Timeout occured for waiting event");
	}
	
	public Lock getConditionPerHandlerLock() {
		return this.conditionPerHandlerLock;
	}
	
	public void signalConditionPerHandler() {
		conditionPerHandlerLock.lock();
		conditionPerHandler.signal();
		conditionPerHandlerLock.unlock();
	}
	
	
	public void setConnected(boolean connected) {
		this.connected = connected;
	}

	public boolean isConnected() {
		return connected;
	}

	private void setErrorMessage(String errorMessage) {
		this.errorMessage = errorMessage;
	}

	public String getErrorMessage() {
		return errorMessage;
	}
	

	@Override
	public synchronized void onConnected(IManagedConnection mconnection) {
		setConnected(true);
		setErrorMessage(null);
		signalCondition();
	}

	@Override
	public synchronized void onConnected(ConnectionHandler handler) {
		addLastHandler(handler);
		signalConditionPerHandler();
	}


	@Override
	public synchronized void onConnectionFailure(IManagedConnection mconnection, String errorMessage) {
		setConnected(false);
		setErrorMessage(errorMessage);
		signalCondition();
	}

	@Override
	public synchronized void onConnectionFailure(ConnectionHandler handler,
			String errorMessage) {
		addLastHandler(handler);
		setErrorMessage(errorMessage);
		signalConditionPerHandler();
	}

	@Override
	public synchronized void onDisconnected(IManagedConnection mconnection) {
		setConnected(false);
		setErrorMessage(null);
		signalCondition();
	}

	@Override
	public synchronized void onDisconnected(ConnectionHandler handler) {
		addLastHandler(handler);
		signalConditionPerHandler();
	}

	@Override
	public synchronized void onReceiveError(ConnectionHandler handler, String errorMessage) {
		addLastHandler(handler);
		setErrorMessage(errorMessage);
		signalCondition();
	}

	@Override
	public synchronized void onReceived(ConnectionHandler handler, ByteBuffer buffer) {
		// TODO Auto-generated method stub

	}

	@Override
	public synchronized void onWriteError(ConnectionHandler handler, String errorMessage) {
		addLastHandler(handler);
		setErrorMessage(errorMessage);
		signalCondition();
	}


	public void setLastHandlers(Collection<ConnectionHandler> lastHandlers) {
		this.lastHandlers = lastHandlers;
	}


	public Collection<ConnectionHandler> getLastHandlers() {
		return lastHandlers;
	}

	private void addLastHandler(ConnectionHandler handler) {
		getLastHandlers().add(handler);
	}

}
